#!/usr/bin/env node

/**
 * FileHive Node.js 后端安全测试脚本
 * 测试路径遍历防护和文件名清理功能
 */

const { validatePath, isValidPath, safePath, sanitizeFilename } = require('./utils');
const path = require('path');

console.log('🔒 FileHive Node.js 后端安全测试');
console.log('=====================================\n');

// 测试基础路径
const basePath = '/var/www/shared-files';

// 测试用例
const pathTests = [
  // 正常路径
  { path: '', description: '空路径', expected: true },
  { path: 'folder', description: '正常文件夹', expected: true },
  { path: 'folder/subfolder', description: '正常子文件夹', expected: true },
  { path: 'file.txt', description: '正常文件', expected: true },
  
  // 路径遍历攻击
  { path: '..', description: '相对路径父目录', expected: false },
  { path: '../', description: '相对路径父目录（带斜杠）', expected: false },
  { path: '../../../etc/passwd', description: '经典路径遍历攻击', expected: false },
  { path: '..\\..\\..\\windows\\system32', description: 'Windows路径遍历', expected: false },
  { path: 'folder/../../../etc/passwd', description: '混合路径遍历', expected: false },
  
  // 绝对路径攻击
  { path: '/etc/passwd', description: '绝对路径（Unix）', expected: false },
  { path: 'C:\\Windows\\System32', description: '绝对路径（Windows）', expected: false },
  { path: 'file:///etc/passwd', description: '文件协议', expected: false },
  { path: 'http://example.com/', description: 'HTTP协议', expected: false },
  
  // 特殊字符攻击
  { path: 'test\x00.txt', description: '空字符注入', expected: false },
  { path: 'test<script>alert(1)</script>', description: 'XSS字符', expected: false },
  { path: 'test|rm -rf /*', description: '命令注入字符', expected: false },
  { path: 'test?query=value', description: '查询字符', expected: false },
  { path: 'test*wildcard', description: '通配符', expected: false },
];

const filenameTests = [
  // 正常文件名
  { filename: 'document.txt', description: '正常文件名' },
  { filename: '测试文档.pdf', description: '中文文件名' },
  { filename: 'IMG_2024_01_01.jpg', description: '带下划线文件名' },
  
  // 危险文件名
  { filename: '../../../etc/passwd', description: '路径遍历文件名' },
  { filename: '<script>alert(1)</script>.txt', description: 'XSS文件名' },
  { filename: 'file|rm -rf /*.txt', description: '命令注入文件名' },
  { filename: '.hidden', description: '隐藏文件' },
  { filename: '...', description: '多个点' },
  { filename: '', description: '空文件名' },
  { filename: '   ', description: '空格文件名' },
  { filename: 'con.txt', description: 'Windows保留名' },
  { filename: 'file with spaces.txt', description: '包含空格文件名' },
  { filename: 'very_long_filename_' + 'x'.repeat(300) + '.txt', description: '超长文件名' },
];

console.log('1. 路径验证测试 (validatePath)');
console.log('----------------------------');

let pathTestsPassed = 0;
let pathTestsTotal = pathTests.length;

for (const test of pathTests) {
  const result = validatePath(test.path);
  const status = result === test.expected ? '✅ PASS' : '❌ FAIL';
  
  if (result === test.expected) {
    pathTestsPassed++;
  }
  
  console.log(`${status} ${test.description}: "${test.path}"`);
  if (result !== test.expected) {
    console.log(`     预期: ${test.expected}, 实际: ${result}`);
  }
}

console.log(`\n路径测试结果: ${pathTestsPassed}/${pathTestsTotal} 通过\n`);

console.log('2. 安全路径构建测试 (safePath)');
console.log('------------------------------');

const safePathTests = [
  'normal/path',
  '../../../etc/passwd',
  '/absolute/path',
  'normal/../traversal',
  ''
];

for (const testPath of safePathTests) {
  const { path: resultPath, safe } = safePath(basePath, testPath);
  const status = safe ? '✅ 安全' : '❌ 危险';
  
  console.log(`${status} "${testPath}"`);
  if (safe) {
    console.log(`     结果路径: ${resultPath}`);
  } else {
    console.log(`     被阻止的危险路径`);
  }
}

console.log('\n3. 文件名清理测试 (sanitizeFilename)');
console.log('------------------------------------');

for (const test of filenameTests) {
  const cleaned = sanitizeFilename(test.filename);
  const changed = cleaned !== test.filename;
  const status = changed ? '🔧 已清理' : '✅ 无需清理';
  
  console.log(`${status} ${test.description}`);
  console.log(`     原始: "${test.filename}"`);
  console.log(`     清理后: "${cleaned}"`);
  console.log('');
}

console.log('4. 边界情况测试');
console.log('----------------');

// 测试 URL 编码的路径遍历
const encodedTests = [
  '%2e%2e%2f',  // ../
  '%2e%2e%5c',  // ..\
  '%2f%2e%2e%2f', // /../
];

console.log('URL编码路径遍历测试:');
for (const encoded of encodedTests) {
  const decoded = decodeURIComponent(encoded);
  const isValid = validatePath(decoded);
  const status = isValid ? '❌ 未检测到' : '✅ 已阻止';
  console.log(`${status} "${encoded}" -> "${decoded}"`);
}

console.log('\n5. 性能测试');
console.log('------------');

const perfStart = Date.now();
const iterations = 10000;

for (let i = 0; i < iterations; i++) {
  validatePath('normal/test/path');
  sanitizeFilename('test_file_name.txt');
  safePath(basePath, 'test/path');
}

const perfEnd = Date.now();
const avgTime = (perfEnd - perfStart) / iterations;

console.log(`${iterations} 次操作总时间: ${perfEnd - perfStart}ms`);
console.log(`平均每次操作时间: ${avgTime.toFixed(3)}ms`);

console.log('\n=====================================');
console.log('🔒 安全测试完成');

if (pathTestsPassed === pathTestsTotal) {
  console.log('✅ 所有路径验证测试通过，安全防护工作正常！');
  process.exit(0);
} else {
  console.log(`❌ ${pathTestsTotal - pathTestsPassed} 个路径验证测试失败，请检查安全配置！`);
  process.exit(1);
} 